package com.chunguang.sxt.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class Server {

	public static void main(String[] args) throws Exception {
		//1 第一个线程组 是用于接收Client端连接的
		EventLoopGroup bossGroup = new NioEventLoopGroup();
		//2 第二个线程组 是用于实际的业务处理操作的
		EventLoopGroup workerGroup = new NioEventLoopGroup();
		
		//3 创建一个辅助类Bootstrap，就是对我们的Server进行一系列的配置
		ServerBootstrap b = new ServerBootstrap(); 
		//把俩个工作线程组加入进来
		b.group(bossGroup, workerGroup)
		//我要指定使用NioServerSocketChannel这种类型的通道
		 .channel(NioServerSocketChannel.class)
		//一定要使用 childHandler 去绑定具体的 事件处理器
		 .childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel sc) throws Exception {
				sc.pipeline().addLast(new ServerHandler());
			}
		})
		 /**
		  * 服务器端TCP内核模块维护两个队列，A,B
		  * 客户端向服务器端连接的时候，会有SYN标志包（第一次握手）
		  * 服务器端接收到客户端发来的SYN时候，向客户端发送SYN ACK 进行确认 （第二次握手）
		  * 此时TCP内核模块开始把客户端放到A队列中，然后服务器接收到客户端的ACK应答时候 （第三次握手）TCP内核模块开始把客户端
		  * 从A队列移动到B队列， 连接完成， 应用程序accept会返回。 
		  * 也就是说accept从B队列中取出握手完成三次的连接。
		  * A队列和B队列长度之和是backlog ，当A,B队列长度之和大于Backlog时候，新连接会被拒绝。
		  * 所以，如果backlog过小的时候可能出现accept速度跟不上，AB队列满了，导致新的客户端无法连接。
		  * 要注意的是：backlog对程序的连接数无影响，backlog影响的只是还没有被accept去除的连接
		  *
		  * 
		  * 
		  */
//			设置tcp连接的缓冲池的大小
		 .option(ChannelOption.SO_BACKLOG, 128)
//		 以后如果有多个通道的时候，就用这个来配置child通道
		 .childOption(ChannelOption.SO_KEEPALIVE,true)
//		配置主server通道的。
		 .option(ChannelOption.SO_KEEPALIVE,true)
		 
		 .option(ChannelOption.SO_SNDBUF, 1024)   
		 
		 .option(ChannelOption.SO_RCVBUF, 1024);
		
		//绑定指定的端口 进行监听  
		//异步的通道						// 异步释放连接的功能。
		
		ChannelFuture f = b.bind(8765).sync(); 
//		ChannelFuture f = b.bind(8365).sync();  这里还可以添加多个bind 端口
//		  这里是异步进行绑定，这里的仍然是继续向下执行的。拿到了未来的feature对象。
		//Thread.sleep(1000000);
		f.channel().closeFuture().sync();
		
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
		 
		
		
	}
	
}
